home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / mus / misc / AmiXpose.lha / AmiXPose / src / xpose.c < prev   
Encoding:
C/C++ Source or Header  |  1995-04-10  |  28.1 KB  |  910 lines

  1. /*********************************************************************
  2. Author      : Charles Bradley Slaten
  3. **********************************************************************
  4. Amiga Port : Peter Herter
  5. *********************************************************************/
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #define MAXLINE 133
  11. #define DEFAULT_WIDTH 72
  12. #define DEFAULT_SKIP_LINES 0
  13. #define DEFAULT_CHORDS_PER_ROW 3
  14. #define COMMENT_CHAR '#'
  15. #define CHORUS_CHAR '|'
  16. #define NEWPAGE 0x0C
  17. #define FLAT_CHAR 'b'
  18. #define LEFT_MARGIN 0
  19. #define FLAT -1
  20. #define NATURAL 0
  21. #define SHARP 1
  22.  
  23. unsigned char versiontag[] = "\0$VER: AmiXPose 1.4 ("__DATE__")";
  24.  
  25. #ifndef TRUE
  26. #define TRUE 1
  27. #endif
  28. #ifndef FALSE
  29. #define FALSE 0
  30. #endif
  31.  
  32. typedef int Boolean;
  33. typedef struct chordStruct {
  34.     char *chordName;
  35.     char fingering[7];
  36.     int offset;
  37. } Chord;
  38. typedef struct chordListStruct {
  39.     Chord *chord;
  40.     struct chordListStruct *next;
  41. } ChordList;
  42.         
  43. ChordList* InChordList[7];
  44. ChordList* KnownChordList[7];
  45.  
  46. char* FlatNotes[] = {"A","Bb","B","C","Db","D","Eb","E","F","Gb","G","Ab" };
  47. char* SharpNotes[] = {"A","A#","B","C","C#","D","D#","E","F","F#","G","G#" };
  48. char* InFileName;
  49. char* OutFileName = "stdout";
  50. char* ChordFileName = NULL;
  51. char Chords[MAXLINE];
  52. char Text[MAXLINE];
  53. char Buffer[MAXLINE];
  54. char* BufferPtr;
  55. char TextSize[MAXLINE];
  56. char ChordSize[MAXLINE];
  57. char TextFont[MAXLINE];
  58. char ChordFont[MAXLINE];
  59. char* TitlePrefix = NULL;
  60. char* TitleSuffix = NULL;
  61. char* SubTitlePrefix = NULL;
  62. char* SubTitleSuffix = NULL;
  63. char* CommentPrefix = "{";
  64. char* CommentSuffix = "}";
  65.  
  66. FILE* InFile;
  67. FILE* OutFile = stdout;
  68.  
  69. Boolean ChorusFlag;
  70. Boolean CenterTitleFlag = FALSE;
  71. Boolean ChordFlag = TRUE;
  72. Boolean FingeringFlag = TRUE;
  73.  
  74. int Transposition = 0;
  75. int TransposeSwitch = FALSE;
  76. int SharpFlatSwitch = FLAT;
  77.  
  78. int chordPosition;
  79. int textPosition;
  80. int NextChordPosition;
  81. int lineNo;
  82. int Width = DEFAULT_WIDTH;
  83. int LeftMargin = LEFT_MARGIN;
  84. int skipLines = DEFAULT_SKIP_LINES;
  85. int ChordsPerRow = DEFAULT_CHORDS_PER_ROW;
  86. int c;
  87.  
  88. int getopt(int argc,char** argv,char* optstring);
  89. void processText(int c);
  90. void clear(char* string,int length);
  91. char* transpose(char* chordIn,short numHalfSteps);
  92. int addChord(char* chordName);
  93. ChordList* searchChordList(char* chordName,ChordList* chordList[]);
  94. void emptyList(ChordList* chordList[]);
  95. void addChordToList(Chord* chordPtr,ChordList* chordList[]);
  96. void initialize();
  97. void processChord();
  98. void processFile();
  99. void processDirective();
  100. void outputLine();
  101. void printMargin();
  102. void bomb();
  103. void processSOC();
  104. void processEOC();
  105. void processTextSize();
  106. void processNewSong();
  107. void processTextFont();
  108. void processTitle();
  109. void processComment();
  110. void processChordSize();
  111. void processDefine();
  112. void processSubtitle();
  113. void processChordFont();
  114. void usage();
  115. void skipToEndOfLine();
  116. void initKnownChords();
  117. void printChordsText();
  118. void dumpChords();
  119.  
  120. /**********************************************************************/
  121. main (int argc, char **argv) {
  122.     int c;
  123.     int errflg = 0;
  124.     Boolean tmpFingeringFlag;
  125.     extern int optind;
  126.     extern char *optarg;
  127.     initKnownChords ();
  128.     initialize ();
  129.     while ((c = getopt (argc, argv, "#bc:C:dDhH:lt:T:24x:o:")) != EOF) {
  130.         switch (c) {
  131.         case '#':
  132.             SharpFlatSwitch = SHARP;
  133.             break;
  134.         case 'b':
  135.             SharpFlatSwitch = FLAT;
  136.             break;
  137.         case 'c':
  138.             strcpy (ChordSize, optarg);
  139.             break;
  140.         case 'C':
  141.             strcpy (ChordFont, optarg);
  142.             break;
  143.         case 'd':
  144.             dumpChords ();
  145.             exit (0);
  146.             break;
  147.         case 'D':
  148.             fprintf (stderr, "Option D not supported.\n");
  149.             break;
  150.         case 'h':
  151.             usage ();
  152.             exit (0);
  153.             break;
  154.         case 'H':
  155.             ChordFileName = optarg;
  156.             break;
  157.         case 'l':
  158.             ChordFlag = FALSE;
  159.             FingeringFlag = FALSE;
  160.             break;
  161.         case 't':
  162.             strcpy (TextSize, optarg);
  163.             break;
  164.         case 'T':
  165.             strcpy (TextFont, optarg);
  166.             break;
  167.         case '2':
  168.             fprintf (stderr, "Option 2 not supported.\n");
  169.             break;
  170.         case '4':
  171.             fprintf (stderr, "Option 4 not supported.\n");
  172.             break;
  173.         case 'x':
  174.             sscanf (optarg, "%d", &Transposition);
  175.             TransposeSwitch = TRUE;
  176.             break;
  177.         case 'o':
  178.             OutFileName = optarg;
  179.             OutFile = fopen (OutFileName, "w");
  180.             if (OutFile == NULL) {
  181.                 fprintf (stderr, "chord:  cannot use %s as output.\n",
  182.                          OutFileName);
  183.                 exit (1);
  184.             } break;
  185.         default:
  186.             errflg++;
  187.             break;
  188.         }
  189.     } if (errflg) {
  190.         usage ();
  191.     } if (optind < argc) {
  192.         /* read in user defined chords */
  193.         InFile = fopen (ChordFileName, "r");
  194.         if (InFile != NULL) {
  195.             /* disable FingeringFlag so that processFile() of chordrc
  196.              * will not attempt to print out fingering charts */
  197.             tmpFingeringFlag = FingeringFlag;
  198.             FingeringFlag = FALSE;
  199.             processFile ();
  200.             /* restore FingeringFlag */
  201.             FingeringFlag = tmpFingeringFlag;
  202.             fclose (InFile);
  203.         } /* else do nothing -- no user defined chord file exists */ while (optind < argc) {
  204.             InFileName = argv[optind];
  205.             InFile = fopen (InFileName, "r");
  206.             if (InFile == NULL) {
  207.                 fprintf (stderr, "chord:  cannot use %s as input.\n",
  208.                          InFileName);
  209.                 exit (1);
  210.             } processFile ();
  211.             fclose (InFile);
  212.             optind++;
  213.             if (optind < argc) {
  214.                 processNewSong ();
  215.             }
  216.         }
  217.     }
  218.     else {
  219.         InFileName = "stdin";
  220.         InFile = stdin;
  221.         processFile ();
  222.     } return (0);
  223. }
  224.  
  225. /**********************************************************************/
  226. void processFile (void) {
  227.     lineNo = 1;
  228.     while ((c = getc (InFile)) != EOF) {
  229.         switch (c) {
  230.         case '[':
  231.             processChord ();
  232.             break;
  233.         case '{':               /* } */
  234.             processDirective ();
  235.             break;
  236.         case '\n':
  237.             outputLine ();
  238.             break;
  239.         default:
  240.             processText (c);
  241.             break;
  242.         }
  243.     } if (FingeringFlag /*== TRUE*/ ) {
  244.         printChordsText ();
  245.     }
  246. }
  247.  
  248. /**********************************************************************/
  249. void initialize() {
  250.     /* clear out the chord and text buffers */
  251.     clear(Chords,MAXLINE);
  252.     clear(Text,MAXLINE);
  253.     chordPosition = textPosition = 0;
  254.     emptyList(InChordList);
  255. }
  256.  
  257. /**********************************************************************/
  258. void processChord () {
  259.     char chordName[MAXLINE];
  260.     char inChordName[MAXLINE];
  261.     char *transposedName;
  262.     short chordNamePosition;
  263.     short inChordNamePosition;
  264.     short i;
  265.  
  266.     chordNamePosition = 0;
  267.     inChordNamePosition = 0;
  268.     if (NextChordPosition > chordPosition) {
  269.         chordPosition = NextChordPosition;
  270.         if (ChordFlag /*== TRUE*/ ) {
  271.             textPosition = chordPosition;
  272.         }
  273.     } while ((c = getc (InFile)) != EOF) {
  274.         /* check for bass notes */
  275.         if (c == '/') {
  276.             chordName[chordNamePosition++] = '\0';
  277.             if (TransposeSwitch /* == TRUE */ ) {
  278.                 transposedName = transpose (chordName, Transposition);
  279.             }
  280.             else {
  281.                 transposedName = chordName;
  282.             } for (i = 0; i < (short) strlen (transposedName); i++) {
  283.                 Chords[chordPosition++] = transposedName[i];
  284.                 inChordName[inChordNamePosition++] = transposedName[i];
  285.             } chordNamePosition = 0;
  286.             Chords[chordPosition++] = '/';
  287.             inChordName[inChordNamePosition++] = '/';
  288.             c = getc (InFile);
  289.         } if (c == ']') {
  290.             chordName[chordNamePosition++] = '\0';
  291.             if (TransposeSwitch /* == TRUE */ ) {
  292.                 transposedName = transpose (chordName, Transposition);
  293.             }
  294.             else {
  295.                 transposedName = chordName;
  296.             } for (i = 0; i < (short) strlen (transposedName); i++) {
  297.                 Chords[chordPosition++] = transposedName[i];
  298.                 inChordName[inChordNamePosition++] = transposedName[i];
  299.             } break;
  300.         } if (c == '\n') {
  301.             bomb ();
  302.         } chordName[chordNamePosition++] = (char) c;
  303.     } /* set next available position for a new chord */ NextChordPosition = chordPosition + 1;
  304.     inChordName[inChordNamePosition] = '\0';
  305.     addChord (inChordName);
  306. }
  307.  
  308. /**********************************************************************/
  309. void processDirective () {
  310.     char keyWord[MAXLINE];
  311.     char *keyWordPtr;
  312.     int bufferPosition;
  313.  
  314.     bufferPosition = 0;
  315.     while ((c = getc (InFile)) != EOF) {
  316.         /* { */
  317.         if (c == '}') {
  318.             break;
  319.         } if (c == ']') {
  320.             bomb ();
  321.         } if (c == '\n') {
  322.             bomb ();
  323.         } Buffer[bufferPosition++] = (char) c;
  324.     } Buffer[bufferPosition++] = '\0';
  325.     keyWordPtr = keyWord;
  326.     BufferPtr = Buffer;
  327.     while ((*BufferPtr != ':') && (*BufferPtr != '\0')) {
  328.         *keyWordPtr = *BufferPtr;
  329.         BufferPtr++;
  330.         keyWordPtr++;
  331.     } *keyWordPtr = '\0';
  332.     /* BufferPtr is pointing at the ':' */
  333.     BufferPtr++;
  334.     /* BufferPtr is pointing at the character after the ':' */
  335.  
  336.     if ((strcmp (keyWord, "start_of_chorus") == 0) ||
  337.         (strcmp (keyWord, "soc") == 0)) {
  338.         processSOC ();
  339.     }
  340.     else if ((strcmp (keyWord, "end_of_chorus") == 0) ||
  341.              (strcmp (keyWord, "eoc") == 0)) {
  342.         processEOC ();
  343.     }
  344.     else if ((strcmp (keyWord, "comment") == 0) ||
  345.              (strcmp (keyWord, "c") == 0)) {
  346.         processComment ();
  347.     }
  348.     else if ((strcmp (keyWord, "new_song") == 0) ||
  349.              (strcmp (keyWord, "ns") == 0)) {
  350.         processNewSong ();
  351.     }
  352.     else if ((strcmp (keyWord, "title") == 0) ||
  353.              (strcmp (keyWord, "t") == 0)) {
  354.         processTitle ();
  355.     }
  356.     else if ((strcmp (keyWord, "subtitle") == 0) ||
  357.              (strcmp (keyWord, "st") == 0)) {
  358.         processSubtitle ();
  359.     }
  360.     else if (strcmp (keyWord, "define") == 0) {
  361.         processDefine ();
  362.     }
  363.     else if (strcmp (keyWord, "textfont") == 0) {
  364.         processTextFont ();
  365.     }
  366.     else if (strcmp (keyWord, "textsize") == 0) {
  367.         processTextSize ();
  368.     }
  369.     else if (strcmp (keyWord, "chordfont") == 0) {
  370.         processChordFont ();
  371.     }
  372.     else if (strcmp (keyWord, "chordsize") == 0) {
  373.         processChordSize ();
  374.     } skipToEndOfLine ();
  375. }
  376.  
  377. /**********************************************************************/
  378. void outputLine () {
  379.     int i;
  380.     if ((chordPosition > 0) || (textPosition > 0)) {
  381.         Chords[chordPosition] = '\0';
  382.         Text[textPosition] = '\0';
  383.         if (ChordFlag /*== TRUE*/ ) {
  384.             if (ChordFont != NULL) {
  385.                 fprintf (OutFile, "%s", ChordFont);
  386.             } if (ChordSize != NULL) {
  387.                 fprintf (OutFile, "%s", ChordSize);
  388.             } printMargin ();
  389.             fprintf (OutFile, "%s\n", Chords);
  390.         } if (TextFont != NULL) {
  391.             fprintf (OutFile, "%s", TextFont);
  392.         } if (TextSize != NULL) {
  393.             fprintf (OutFile, "%s", TextSize);
  394.         } printMargin ();
  395.         fprintf (OutFile, "%s\n", Text);
  396.         chordPosition = textPosition = NextChordPosition = 0;
  397.         clear (Chords, MAXLINE);
  398.         clear (Text, MAXLINE);
  399.     }
  400.     else {
  401.         fprintf (OutFile, "\n");
  402.     } for (i = 0; i < skipLines; i++) {
  403.         if (ChorusFlag /*== TRUE*/ ) {
  404.             printMargin ();
  405.         } fprintf (OutFile, "\n");
  406.     } lineNo++;
  407. }
  408.  
  409. /**********************************************************************/
  410. void printMargin () {
  411.     int i;
  412.     for (i = 0; i < LeftMargin; i++) {
  413.         fprintf (OutFile, " ");
  414.     } if (ChorusFlag /*== TRUE*/ ) {
  415.         fprintf (OutFile, "%c", CHORUS_CHAR);
  416.     }
  417.     else {
  418.         fprintf (OutFile, " ");
  419.     }
  420. }
  421.  
  422. /**********************************************************************/
  423. void processText (int c) {
  424.     if (c == COMMENT_CHAR) {
  425.         if (textPosition == 0) {
  426.             while (getc (InFile) != '\n');
  427.         }
  428.     }
  429.     else {
  430.         Text[textPosition++] = c;
  431.         chordPosition = textPosition;
  432.     }
  433. }
  434.  
  435. /**********************************************************************/
  436. void bomb() {
  437.     fprintf(stderr,"chord: Invalid input on line %d\n",lineNo);
  438.     exit(1);
  439. }
  440.  
  441. /**********************************************************************/
  442. void clear(char* string,int length) {
  443.     int i;
  444.  
  445.     for (i=0;i < length;i++) {
  446.         string[i] = ' ';
  447.     }
  448. }
  449.  
  450. /**********************************************************************/
  451. void processSOC() {
  452.     ChorusFlag = TRUE;
  453. }
  454.  
  455. /**********************************************************************/
  456. void processEOC() {
  457.     ChorusFlag = FALSE;
  458. }
  459.  
  460. /**********************************************************************/
  461. void processTextSize() {
  462.     strcpy(TextSize,BufferPtr);
  463. }
  464.  
  465. /**********************************************************************/
  466. void processTextFont() {
  467.     strcpy(TextFont,BufferPtr);
  468. }
  469.  
  470. /**********************************************************************/
  471. void processNewSong() {
  472.     fprintf(OutFile,"%c",NEWPAGE);
  473.     initialize();
  474. }
  475.  
  476. /**********************************************************************/
  477. void processTitle () {
  478.     int leftMargin;
  479.     int i;
  480.     if (CenterTitleFlag /*== TRUE*/ ) {
  481.         leftMargin = (Width - (int) strlen (BufferPtr)) / 2;
  482.         for (i = 0; i < leftMargin; i++) {
  483.             fprintf (OutFile, " ");
  484.         }
  485.     } if (TitlePrefix != NULL) {
  486.         fprintf (OutFile, TitlePrefix);
  487.     } fprintf (OutFile, BufferPtr);
  488.     if (TitleSuffix != NULL) {
  489.         fprintf (OutFile, TitleSuffix);
  490.     } fprintf (OutFile, "\n");
  491. }
  492.  
  493. /**********************************************************************/
  494. void processSubtitle () {
  495.     int leftMargin;
  496.     int i;
  497.     if (CenterTitleFlag /*== TRUE*/ ) {
  498.         leftMargin = (Width - (int) strlen (BufferPtr)) / 2;
  499.         for (i = 0; i < leftMargin; i++) {
  500.             fprintf (OutFile, " ");
  501.         }
  502.     } if (SubTitlePrefix != NULL) {
  503.         fprintf (OutFile, SubTitlePrefix);
  504.     } fprintf (OutFile, BufferPtr);
  505.     if (SubTitleSuffix != NULL) {
  506.         fprintf (OutFile, SubTitleSuffix);
  507.     } fprintf (OutFile, "\n");
  508. } /**********************************************************************/ void processComment ()
  509. {
  510.     printMargin ();
  511.     if (CommentPrefix != NULL) {
  512.         fprintf (OutFile, CommentPrefix);
  513.     } fprintf (OutFile, BufferPtr);
  514.     if (CommentSuffix != NULL) {
  515.         fprintf (OutFile, CommentSuffix);
  516.     } fprintf (OutFile, "\n");
  517. }
  518.  
  519. /**********************************************************************/
  520. void processChordSize() {
  521.     strcpy(ChordSize,BufferPtr);
  522. }
  523.  
  524. /**********************************************************************/
  525. void processChordFont() {
  526.     strcpy(ChordFont,BufferPtr);
  527. }
  528.  
  529. /**********************************************************************/
  530. void processDefine () {
  531.     char *chordName;
  532.     int e1, a, d, g, b, e2, offset;
  533.  
  534.     chordName = strtok (BufferPtr, " ,}");
  535.     e1 = atoi (strtok (NULL, " ,}"));
  536.     a = atoi (strtok (NULL, " ,}"));
  537.     d = atoi (strtok (NULL, " ,}"));
  538.     g = atoi (strtok (NULL, " ,}"));
  539.     b = atoi (strtok (NULL, " ,}"));
  540.     e2 = atoi (strtok (NULL, " ,}"));
  541.     offset = atoi (strtok (NULL, " ,}"));
  542.     learnChord (chordName, (char) e1, (char) a, (char) d, (char) g, (char) b,
  543.                 (char) e2);
  544. }
  545.  
  546. /**********************************************************************/
  547. char *transpose (char *chordIn, short numHalfSteps) {
  548.     char *currPtr;
  549.     char chordRoot;
  550.     static char newChord[16];
  551.     currPtr = chordIn;
  552.     /* check for valid chord */
  553.     if (islower (*currPtr)) {
  554.         chordRoot = toupper (*currPtr);
  555.     }
  556.     else {
  557.         chordRoot = *currPtr;
  558.     } if ((chordRoot >= 'A') && (chordRoot <= 'G')) {
  559.         switch (chordRoot) {
  560.         case 'A':
  561.         case 'B':
  562.             chordRoot = (chordRoot - 'A') * 2;
  563.             break;
  564.         case 'C':
  565.         case 'D':
  566.         case 'E':
  567.             chordRoot = ((chordRoot - 'A') * 2) - 1;
  568.             break;
  569.         case 'F':
  570.         case 'G':
  571.             chordRoot = ((chordRoot - 'A') * 2) - 2;
  572.             break;
  573.         } currPtr++;
  574.         if (*currPtr != '\0') {
  575.             if (*currPtr == '#') {
  576.                 chordRoot++;
  577.                 /* make currPtr point to remainder of the chord */
  578.                 currPtr++;
  579.             }
  580.             else if (*currPtr == FLAT_CHAR) {
  581.                 chordRoot--;
  582.                 /* make currPtr point to remainder of the chord */
  583.                 currPtr++;
  584.             }
  585.         } chordRoot += numHalfSteps;
  586.         /* adjust for wrap past G */
  587.         if (chordRoot > 11) {
  588.             chordRoot %= 12;
  589.         } /* adjust for wrap below A */ 
  590.         else
  591.             while (chordRoot < 0) {
  592.                 chordRoot += 12;
  593.         } if (SharpFlatSwitch == FLAT) {
  594.             sprintf (newChord, "%s%s", FlatNotes[chordRoot], currPtr);
  595.         }
  596.         else {
  597.             sprintf (newChord, "%s%s", SharpNotes[chordRoot], currPtr);
  598.         }
  599.     }
  600.     else {
  601.         strcpy (newChord, chordIn);
  602.     } return (newChord);
  603. }
  604.  
  605. /**********************************************************************/
  606. void usage(void) {
  607.     fprintf(stderr,"chord usage:\n");
  608.     fprintf(stderr,"arg\t\t\t\tMeaning\n");
  609.     fprintf(stderr,"---\t\t\t\t-------\n");
  610.     fprintf(stderr,"-#\t\tPrint chords using sharps\n");
  611.     fprintf(stderr,"-b\t\tPrint chords using flats\n");
  612.     fprintf(stderr,"-c text\t\tText to be printed on the \"chord\" lines.\n");
  613.     fprintf(stderr,"\t\t    This text can be used to set the font size.\n");
  614.     fprintf(stderr,"-C text\t\tText to be printed on the \"chord\" lines.\n");
  615.     fprintf(stderr,"\t\t    This text can be used to set the font.\n");
  616.     fprintf(stderr,"-d\t\tDumps the list and description of all\n");
  617.     fprintf(stderr,"\t\t    internally known chords\n");
  618.     fprintf(stderr,"-D\t\tPrints debugging information.\n");
  619.     fprintf(stderr,"\t\t    For programmers only.  Not implemented.\n");
  620.     fprintf(stderr,"-h\t\tPrints a short options summary.\n");
  621.     fprintf(stderr,"-l\t\tPrints only the lyrics of the song.\n");
  622.     fprintf(stderr,"-t text\t\tText to be printed on the \"text\" lines.\n");
  623.     fprintf(stderr,"\t\t    This text can be used to set the font size.\n");
  624.     fprintf(stderr,"-T text\t\tText to be printed on the \"text\" lines.\n");
  625.     fprintf(stderr,"\t\t    This text can be used to set the font.\n");
  626.     fprintf(stderr,"-2\t\tPrints two logical pages per physical page.\n");
  627.     fprintf(stderr,"\t\t    Not implemented.\n");
  628.     fprintf(stderr,"-4\t\tPrints four logical pages per physical page.\n");
  629.     fprintf(stderr,"\t\t    Not implemented.\n");
  630.     fprintf(stderr,"-x[+|-]number\tTransposes all chords up or down\n");
  631.     fprintf(stderr,"\t\t    this number of half-steps\n");
  632. }
  633.  
  634. /**********************************************************************/
  635. void skipToEndOfLine() {
  636.     int c;
  637.  
  638.     while (((c = getc(InFile)) != EOF) && (c != '\n')) {
  639.     }
  640. }
  641.  
  642. /**********************************************************************/
  643. int addChord (char *chordName) {
  644.     ChordList *chordListPtr;
  645.     /* search for chord in the known chords */
  646.     if ((chordListPtr = searchChordList (chordName, KnownChordList)) != NULL) {
  647.         if (searchChordList (chordName, InChordList) == NULL) {
  648.             while ((chordListPtr != NULL) &&
  649.                 (strcmp (chordName, chordListPtr->chord->chordName) == 0)) {
  650.                 addChordToList (chordListPtr->chord, InChordList);
  651.                 chordListPtr = chordListPtr->next;
  652.             }
  653.         }
  654.     }
  655. }
  656.  
  657. /**********************************************************************/
  658. void emptyList (ChordList * chordList[]) {
  659.     int i;
  660.     ChordList *currPtr;
  661.     ChordList *nextCurrPtr;
  662.     for (i = 0; i < 7; i++) {
  663.         currPtr = chordList[i];
  664.         chordList[i] = NULL;
  665.         while (currPtr != NULL) {
  666.             nextCurrPtr = currPtr->next;
  667.             free (currPtr);
  668.             currPtr = nextCurrPtr;
  669.         }
  670.     }
  671. }
  672.  
  673. /**********************************************************************/
  674. ChordList *searchChordList (char *chordName, ChordList * chordList[]) {
  675.     char *currPtr;
  676.     char chordRoot;
  677.     ChordList *list;
  678.     currPtr = chordName;
  679.     /* check for valid chord */
  680.  
  681.     if (islower (*currPtr)) {
  682.         chordRoot = toupper (*currPtr);
  683.     }
  684.     else {
  685.         chordRoot = *currPtr;
  686.     } if ((chordRoot >= 'A') && (chordRoot <= 'G')) {
  687.         /* search the list for the chord fingering */
  688.         list = chordList[chordRoot - 'A'];
  689.         while (list != NULL) {
  690.             if (strcmp (list->chord->chordName, chordName) == 0) {
  691.                 break;
  692.             } list = list->next;
  693.         } if (list != NULL) {
  694.             return (list);
  695.         }
  696.         else {
  697.             return (NULL);
  698.         }
  699.     }
  700.     else {
  701.         return (NULL);
  702.     }
  703. }
  704.  
  705. /**********************************************************************/
  706. void addChordToList (Chord * chordPtr, ChordList * chordList[]) {
  707.     char *currPtr;
  708.     char chordRoot;
  709.     ChordList *newChordListElement;
  710.     ChordList *tmpPtr;
  711.     ChordList *foundChordListElement;
  712.  
  713.     currPtr = chordPtr->chordName;
  714.     /* check for valid chord */
  715.     if (islower (*currPtr)) {
  716.         chordRoot = toupper (*currPtr);
  717.     }
  718.     else {
  719.         chordRoot = *currPtr;
  720.     } if ((chordRoot >= 'A') && (chordRoot <= 'G')) {
  721.         /* search the list for the chord fingering */
  722.         if ((foundChordListElement = searchChordList (chordPtr->
  723.                                            chordName, chordList)) == NULL) {
  724.             newChordListElement = (ChordList *) malloc (sizeof (ChordList));
  725.             newChordListElement->chord = chordPtr;
  726.             tmpPtr = chordList[chordRoot - 'A'];
  727.             chordList[chordRoot - 'A'] = newChordListElement;
  728.             newChordListElement->next = tmpPtr;
  729.         }
  730.         else {
  731.             newChordListElement = (ChordList *) malloc (sizeof (ChordList));
  732.             newChordListElement->chord = chordPtr;
  733.             newChordListElement->next = foundChordListElement->next;
  734.  
  735.             foundChordListElement->next = newChordListElement;
  736.         }
  737.     }
  738. }
  739.  
  740. /**********************************************************************/
  741. void initKnownChords() {
  742.     learnChord("Ab",1,3,3,2,1,1,4);
  743.     learnChord("Ab7",-1,-1,1,1,1,2,1);
  744.     learnChord("Absus",-1,-1,1,1,2,4,1);
  745.     learnChord("Ab+",-1,-1,2,1,1,0,1);
  746.     learnChord("Abmaj7",-1,-1,1,1,1,3,1);
  747.     learnChord("A",-1,0,2,2,2,0,1);
  748.     learnChord("Am",-1,0,2,2,1,0,1);
  749.     learnChord("A7",-1,0,2,0,2,0,1);
  750.     learnChord("Am7",-1,0,2,2,1,3,1);
  751.     learnChord("Asus",-1,-1,2,2,3,0,1);
  752.     learnChord("A+",-1,0,3,2,2,1,1);
  753.     learnChord("Adim",-1,-1,1,2,1,2,1);
  754.     learnChord("Amaj7",-1,0,2,1,2,0,1);
  755.     learnChord("Bb",-1,1,3,3,3,1,1);
  756.     learnChord("Bbm",-1,1,3,3,2,1,1);
  757.     learnChord("Bb7",-1,-1,1,1,1,2,3);
  758.     learnChord("Bbm7",-1,1,3,1,2,1,1);
  759.     learnChord("Bbsus",-1,-1,3,3,4,1,1);
  760.     learnChord("Bb+",-1,-1,0,3,3,2,1);
  761.     learnChord("Bbdim",-1,-1,2,3,2,3,1);
  762.     learnChord("Bbmaj7",-1,1,3,2,3,-1,1);
  763.     learnChord("B",-1,2,4,4,4,2,1);
  764.     learnChord("Bm",-1,2,4,4,3,2,1);
  765.     learnChord("B7",0,2,1,2,0,2,1);
  766.     learnChord("Bm7",-1,1,3,1,2,1,2);
  767.     learnChord("Bsus",-1,-1,3,3,4,1,2);
  768.     learnChord("B+",-1,-1,1,0,0,4,1);
  769.     learnChord("Bdim",-1,-1,0,1,0,1,1);
  770.     learnChord("Bmaj7",-1,2,4,3,4,-1,1);
  771.     learnChord("C",0,3,2,0,1,0,1);
  772.     learnChord("Cm",-1,1,3,3,2,1,3);
  773.     learnChord("C7",0,3,2,3,1,0,1);
  774.     learnChord("Cm7",-1,1,3,1,2,1,3);
  775.     learnChord("Csus",-1,-1,3,0,1,3,1);
  776.     learnChord("C+",-1,-1,2,1,1,0,1);
  777.     learnChord("Cdim",-1,-1,1,2,1,2,1);
  778.     learnChord("Cmaj7",-1,3,2,0,0,0,1);
  779.     learnChord("C#m",-1,-1,2,1,2,0,1);
  780.     learnChord("C#m7",-1,-1,2,4,2,4,1);
  781.     learnChord("C#dim",-1,-1,2,3,2,3,1);
  782.     learnChord("Db",-1,-1,3,1,2,1,1);
  783.     learnChord("Db7",-1,-1,3,4,2,4,1);
  784.     learnChord("Dbsus",-1,-1,3,3,4,1,4);
  785.     learnChord("Dbdim",-1,-1,2,3,2,3,1);
  786.     learnChord("Dbmaj7",-1,4,3,1,1,1,1);
  787.     learnChord("D",-1,-1,0,2,3,2,1);
  788.     learnChord("Dm",-1,-1,0,2,3,1,1);
  789.     learnChord("D7",-1,-1,0,2,1,2,1);
  790.     learnChord("Dm7",-1,-1,0,2,1,1,1);
  791.     learnChord("Dsus",-1,-1,0,2,3,3,1);
  792.     learnChord("D+",-1,-1,0,3,3,2,1);
  793.     learnChord("Ddim",-1,-1,0,1,0,1,1);
  794.     learnChord("Dmaj7",-1,-1,0,1,1,1,1);
  795.     learnChord("D#dim",-1,-1,1,2,1,2,1);
  796.     learnChord("Eb",-1,-1,3,1,2,1,3);
  797.     learnChord("Ebm",-1,-1,4,3,4,2,1);
  798.     learnChord("Eb7",-1,-1,1,3,2,3,1);
  799.     learnChord("Ebm7",-1,-1,1,3,2,2,1);
  800.     learnChord("Ebsus",-1,-1,1,3,4,4,1);
  801.     learnChord("Eb+",-1,-1,1,0,0,4,1);
  802.     learnChord("Ebmaj7",-1,-1,1,3,3,3,1);
  803.     learnChord("E",0,2,2,1,0,0,1);
  804.     learnChord("Em",0,2,2,0,0,0,1);
  805.     learnChord("E7",0,2,2,1,3,0,1);
  806.     learnChord("Em7",0,2,2,0,3,0,1);
  807.     learnChord("Esus",0,2,2,2,0,0,1);
  808.     learnChord("E+",-1,-1,2,1,1,0,1);
  809.     learnChord("Edim",-1,-1,2,3,2,3,1);
  810.     learnChord("Emaj7",0,2,1,1,0,-1,1);
  811.     learnChord("F",1,3,3,2,1,1,1);
  812.     learnChord("Fm",1,3,3,1,1,1,1);
  813.     learnChord("F7",1,3,1,2,1,1,1);
  814.     learnChord("Fm7",1,3,1,1,1,1,1);
  815.     learnChord("Fsus",-1,-1,3,3,1,1,1);
  816.     learnChord("F+",-1,-1,3,2,2,1,1);
  817.     learnChord("Fdim",-1,-1,0,1,0,1,1);
  818.     learnChord("Fmaj7",-1,3,3,2,1,0,1);
  819.     learnChord("Gbmaj7",-1,-1,4,3,2,1,1);
  820.     learnChord("G",3,2,0,0,0,3,1);
  821.     learnChord("Gm",1,3,3,1,1,1,3);
  822.     learnChord("G7",3,2,0,0,0,1,1);
  823.     learnChord("Gm7",1,3,1,1,1,1,3);
  824.     learnChord("Gsus",-1,-1,0,0,1,3,1);
  825.     learnChord("G+",-1,-1,1,0,0,4,1);
  826.     learnChord("Gdim",-1,-1,2,3,2,3,1);
  827.     learnChord("Gmaj7",-1,-1,1,2,3,4,2);
  828.     learnChord("G#m",1,3,3,1,1,1,4);
  829.     learnChord("G#m7",-1,-1,1,1,1,1,4);
  830.     learnChord("G#dim",-1,-1,0,1,0,1,1);
  831.  
  832.     ChordFileName = (char*)malloc(strlen("s:.chordrc") + 1);
  833.     strcpy(ChordFileName,"s:.chordrc");
  834. }
  835.  
  836. /**********************************************************************/
  837. learnChord(char* chord,int e1,int a,int d,int g,int b,int e2,int offset) {
  838.     Chord* newChord;
  839.  
  840.     newChord = (Chord*) malloc(sizeof(Chord));
  841.     newChord->chordName = (char*)malloc(strlen(chord) + 1);
  842.     strcpy(newChord->chordName,chord);
  843.     newChord->fingering[0] = (char)e1;
  844.     newChord->fingering[1] = (char)a;
  845.     newChord->fingering[2] = (char)d;
  846.     newChord->fingering[3] = (char)g;
  847.     newChord->fingering[4] = (char)b;
  848.     newChord->fingering[5] = (char)e2;
  849.     newChord->fingering[6] = '\0';
  850.     newChord->offset = offset;
  851.     addChordToList(newChord,KnownChordList);
  852. }
  853.  
  854. /**********************************************************************/
  855. void printChordsText () {
  856.     int i, j, lines, across;
  857.     ChordList *currPtr;
  858.  
  859.     fprintf (OutFile, "\n");
  860.     for (lines = 1; lines < skipLines; lines++) {
  861.         fprintf (OutFile, "\n");
  862.     } across = 0;
  863.     for (i = 0; i < 7; i++) {
  864.         currPtr = InChordList[i];
  865.         while (currPtr != NULL) {
  866.             if ((across / ChordsPerRow) >= 1) {
  867.                 across = 1;
  868.                 fprintf (OutFile, "\n");
  869.                 for (lines = 1; lines < skipLines; lines++) {
  870.                     fprintf (OutFile, "\n");
  871.                 }
  872.             }
  873.             else {
  874.                 across++;
  875.             } fprintf (OutFile, "%6s - ", currPtr->chord->chordName);
  876.             for (j = 0; j < 6; j++) {
  877.                 if (currPtr->chord->fingering[j] >= 0) {
  878.                     fprintf (OutFile, "%d ",
  879.                              currPtr->chord->fingering[j] +
  880.                              currPtr->chord->offset - 1);
  881.                 }
  882.                 else {
  883.                     fprintf (OutFile, "X ");
  884.                 }
  885.             } fprintf (OutFile, "   ");
  886.             currPtr = currPtr->next;
  887.         }
  888.     } fprintf (OutFile, "\n");
  889. }
  890.  
  891. /**********************************************************************/
  892. void dumpChords () {
  893.     int i, j;
  894.     ChordList *currPtr;
  895.  
  896.     for (i = 0; i < 7; i++) {
  897.         currPtr = KnownChordList[i];
  898.         while (currPtr != NULL) {
  899.             fprintf (OutFile, " %s\t\t", currPtr->chord->chordName);
  900.             for (j = 0; j < 6; j++) {
  901.                 fprintf (OutFile, "  %2d",
  902.                          currPtr->chord->fingering[j]);
  903.             } fprintf (OutFile, "\t\t%2d\n",
  904.                        currPtr->chord->offset);
  905.             currPtr = currPtr->next;
  906.         }
  907.     } fprintf (OutFile, "\n");
  908. }
  909.  
  910.